﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Data.Entity;
using System.Linq.Expressions;
using System.Data;
using System.Linq.Dynamic;
using EntityFramework.Extensions;
using System.Reflection;
using MySql.Data.MySqlClient;
using Teamwish.Domain.IBLL;
/************************************************
◇作者： LowKeyC  需要引用这个程序集:EntityFramework.Extended.6.1.0.168
◇说明： 实现EF通用的CRUD通用的接口  
◇版本号：V1.0   
◇创建日期：2017年6月22日 星期四
*****************************************************/
namespace Teamwish.Domain.BLL
{
    public class BaseBLL<T> : IBaseBLL<T>, IDisposable where T:class
    {
        //此处进行调用EF的DBContent 的实体类或者通过工厂化模式来进行调用。
        private readonly DbContext db;
        public BaseBLL(DbContext _db)
        {
            db = _db;
        }
        /// <summary>
        /// 添加一个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Entity"></param>
        /// <returns></returns>
        public bool Add(T Entity) 
        {
            using (TransactionScope Ts = new TransactionScope(TransactionScopeOption.Required))
            {
                db.Set<T>().Add(Entity);
                int Count = db.SaveChanges();
                Ts.Complete();
                return Count > 0;
            }
        }

        /// <summary>
        /// 批量的插入数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Entity"></param>
        /// <returns></returns>
        public bool AddRange(List<T> Entity) 
        {
            using (TransactionScope Ts = new TransactionScope(TransactionScopeOption.Required))
            {
                db.Set<T>().AddRange(Entity);
                int Count = db.SaveChanges();
                Ts.Complete();
                return Count > 0;
            }
        }

        /// <summary>
        /// 根据查询条件进行删除对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="whereLambda">查询条件</param>
        /// <returns></returns>
        public bool Delete(Expression<Func<T, bool>> whereLambda) 
        {
            using (TransactionScope Ts = new TransactionScope(TransactionScopeOption.Required))
            {
                var EntityModel = db.Set<T>().Where(whereLambda).FirstOrDefault();
                if (EntityModel != null)
                {
                    db.Set<T>().Remove(EntityModel);
                    int Count = db.SaveChanges();
                    Ts.Complete();
                    return Count > 0;
                }
                return false;
            }
        }


        /// <summary>
        /// 删除单个对象的实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Entity">实体对象</param>
        /// <returns></returns>
        public bool Delete(T Entity) 
        {
            using (TransactionScope Ts = new TransactionScope(TransactionScopeOption.Required))
            {
                db.Set<T>().Attach(Entity);
                db.Set<T>().Remove(Entity);
                int Count = db.SaveChanges();
                Ts.Complete();
                return Count > 0;
            }
        }

        /// <summary>
        /// 批量的进行更新数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Entity"></param>
        /// <returns></returns>
        public bool Update(List<T> Entity) 
        {
            int Count = 0;
            using (TransactionScope Ts = new TransactionScope(TransactionScopeOption.Required))
            {
                if (Entity != null)
                {
                    foreach (var items in Entity)
                    {
                        var EntityModel = db.Entry(Entity);
                        db.Set<T>().Attach(items);
                        EntityModel.State = EntityState.Modified;
                    }

                }
                Count = db.SaveChanges();
                Ts.Complete();
            }

            return Count > 0;
        }


        /// <summary>
        /// 进行修改单个实体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Entity">实体对象</param>
        /// <returns></returns>
        public bool Update(T Entity) 
        {
            using (TransactionScope Ts = new TransactionScope())
            {
                var EntityModel = db.Entry<T>(Entity);
                db.Set<T>().Attach(Entity);
                EntityModel.State = EntityState.Modified;
                int Count = db.SaveChanges();
                Ts.Complete();
                return Count > 0;
            }
        }

        /// <summary>
        /// 批量的修改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="WhereLambda"></param>
        /// <param name="UpdateLambda"></param>
        /// <returns></returns>
        public bool Update(Expression<Func<T, bool>> WhereLambda, Expression<Func<T, T>> UpdateLambda) 
        {
            db.Set<T>().Where(WhereLambda).Update<T>(UpdateLambda);
            return db.SaveChanges() > 0;
        }


        /// <summary>
        /// 查询条件进行修改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <param name="WhereLambda"></param>
        /// <param name="ModifiedProNames"></param>
        /// <returns></returns>
        public bool Update(T model, Expression<Func<T, bool>> WhereLambda, params string[] ModifiedProNames) 
        {
            //查询要修改的数据
            List<T> ListModifing = db.Set<T>().Where(WhereLambda).ToList();
            Type t = typeof(T);
            List<PropertyInfo> ProInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
            Dictionary<string, PropertyInfo> DitProList = new Dictionary<string, PropertyInfo>();
            ProInfos.ForEach(p =>
            {
                if (ModifiedProNames.Contains(p.Name))
                {
                    DitProList.Add(p.Name, p);
                }
            });

            if (DitProList.Count <= 0)
            {
                throw new Exception("指定修改的字段名称有误或为空");
            }
            foreach (var item in DitProList)
            {
                PropertyInfo proInfo = item.Value;
                object newValue = proInfo.GetValue(model, null);
                //批量进行修改相互对应的属性
                foreach (T oModel in ListModifing)
                {
                    proInfo.SetValue(oModel, newValue, null);//设置其中新的值
                }
            }

            return db.SaveChanges() > 0;
        }
        /// <summary>
        /// 释放缓存
        /// </summary>
        public void Dispose()
        {
            db.Dispose();
        }

        /// <summary>
        /// 查询单个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ID">主键ID</param>
        /// <returns></returns>
        public T FindByID(dynamic ID) 
        {
            return db.Set<T>().Find(ID) ?? null;
        }


        /// <summary>
        /// 获取全部数据的列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Order">排序</param>
        /// <returns></returns>
        public List<T> GetAll(string Order = null) 
        {
            return Order != null ? db.Set<T>().OrderBy(Order).ToList() ?? null : db.Set<T>().ToList() ?? null;
        }

        /// <summary>
        ///根据查询条件进行查询列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="WhereLambda"></param>
        /// <returns></returns>
        public List<T> GetAllQuery(Expression<Func<T, bool>> WhereLambda = null) 
        {
            return WhereLambda != null ? db.Set<T>().Where(WhereLambda).ToList() ?? null : db.Set<T>().ToList() ?? null;
        }

        /// <summary>
        ///判断对象是否存在
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="WhereLambda"></param>
        /// <returns></returns>
        public bool IsExist(Expression<Func<T, bool>> WhereLambda = null) 
        {
            return WhereLambda != null ? db.Set<T>().Where(WhereLambda).Any() : db.Set<T>().Any();
        }

        /// <summary>
        /// 获取查询条件的记录数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="WhereLambda"></param>
        /// <returns></returns>
        public int GetCount(Expression<Func<T, bool>> WhereLambda = null) 
        {
            return WhereLambda != null ? db.Set<T>().Where(WhereLambda).Count() : db.Set<T>().Count();
        }


        /// <summary>
        /// 获取单条的记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="WhereLambda"></param>
        /// <returns></returns>
        public T GetFristDefault(Expression<Func<T, bool>> WhereLambda = null) 
        {
            return WhereLambda != null ? db.Set<T>().Where(WhereLambda).FirstOrDefault() ?? null : db.Set<T>().FirstOrDefault() ?? null;
        }


        /// <summary>
        /// 查询对象的转化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="WhereLambda"></param>
        /// <returns></returns>
        public List<T> GetSelect(Expression<Func<T, bool>> WhereLambda) 
        {
            return db.Set<T>().Where(WhereLambda).ToList() ?? null;
        }

        /// <summary>
        ///根据查询条件进行分页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="PageIndex">当前页</param>
        /// <param name="PageSize">每页的大小</param>
        /// <param name="TotalCount">总记录数</param>
        /// <param name="ordering">排序条件</param>
        /// <param name="WhereLambda">查询条件</param>
        /// <returns></returns>
        public List<T> Pagination(int PageIndex, int PageSize, out int TotalCount, string Ordering, Expression<Func<T, bool>> WhereLambda = null) 
        {
            //分页的时候一定要注意 Order 一定在Skip 之前
            var QueryList = db.Set<T>().OrderBy(Ordering);
            if (WhereLambda != null)
            {
                QueryList = QueryList.Where(WhereLambda);
            }

            TotalCount = QueryList.Count();
            return QueryList.Skip(PageSize * (PageIndex - 1)).Take(PageSize).ToList() ?? null;
        }

        /// <summary>
        ///根据查询条件进行分页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="PageIndex">当前页</param>
        /// <param name="PageSize">每页的大小</param>
        /// <param name="TotalCount">总记录数</param>
        /// <param name="OrderBy">排序条件</param>
        /// <param name="WhereLambda">查询的条件</param>
        /// <param name="IsOrder"></param>
        /// <returns></returns>
        public List<T> Pagination<TKey>(int PageIndex, int PageSize, out int TotalCount, Expression<Func<T, TKey>> OrderBy, Expression<Func<T, bool>> WhereLambda = null, bool IsOrder = true) 
        {
            //分页的时候一定要注意 Order一定在Skip 之前
            IQueryable<T> QueryList = IsOrder == true ? db.Set<T>().OrderBy(OrderBy) : db.Set<T>().OrderByDescending(OrderBy);

            if (WhereLambda != null)
            {
                QueryList = QueryList.Where(WhereLambda);
            }

            TotalCount = QueryList.Count();
            return QueryList.Skip(PageSize * (PageIndex - 1)).Take(PageSize).ToList() ?? null;
        }


        /// <summary>
        /// 执行存储过程的SQL 语句
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Sql">执行的SQL语句</param>
        /// <param name="Parms">SQL 语句的参数</param>
        /// <param name="CmdType"></param>
        /// <returns></returns>
        public List<T> QueryPro(string Sql, List<MySqlParameter> Parms, CommandType CmdType = CommandType.Text) 
        {
            //进行执行存储过程
            if (CmdType == CommandType.StoredProcedure)
            {
                StringBuilder paraNames = new StringBuilder();
                foreach (var item in Parms)
                {
                    paraNames.Append($" @{item},");
                }
                Sql = paraNames.Length > 0 ? $"exec {Sql} {paraNames.ToString().Trim(',')}" : $"exec {Sql} ";
            }
            return db.Set<T>().SqlQuery(Sql, Parms.ToArray()).ToList();
        }


        /// <summary>
        /// 进行回滚
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void RollBackChanges() 
        {
            var Query = db.ChangeTracker.Entries().ToList();

            Query.ForEach(p => p.State = EntityState.Unchanged);
        }

    }
}